#! /usr/bin/env python

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import math as m
import colors
import plane as pl
import pprint
import cmath

pl.use_plotter = 'tkinter'

def addition(x1, y1, x2, y2):
	return x1+x2, y1+y2

def subtraction(x1, y1, x2, y2):
	return x1-x2, y1-y2

def multiplication(x1, y1, x2, y2):
	return x1*x2-y1*y2, y1*x2+x1*y2

def division(x1, y1, x2, y2):
	den = float(x2**2 + y2**2)
	x, y = multiplication(float(x1), float(y1), float(x2), float(-y2))
	return x/den, y/den

def exponential(x, y):
	p = m.e**x
	return p*m.cos(y), p*m.sin(y)

def sin(x, y):
	nx, ny = multiplication(0, 1, x, y)
	nx2, ny2 = multiplication(0, -1, x, y)
	nx, ny = exponential(nx, ny)
	nx2, ny2 = exponential(nx2, ny2)
	nx, ny = subtraction(nx, ny, nx2, ny2)
	return division(nx, ny, 0, 2)

def cos(x, y):
	nx, ny = multiplication(0, 1, x, y)
	nx2, ny2 = multiplication(0, -1, x, y)
	nx, ny = exponential(nx, ny)
	nx2, ny2 = exponential(nx2, ny2)
	nx, ny = addition(nx, ny, nx2, ny2)
	return division(nx, ny, 2, 0)

def nthroot(x, y, k, n):
	a = m.atan2(y, x)
	r = m.hypot(x, y)
	return r**(1./n)*m.cos((a+2*k*m.pi)/n), r**(1./n)*m.sin((a+2*k*m.pi)/n)

def power(x, y, n):
	a = m.atan2(y, x)
	r = m.hypot(x, y)
	rn = r**n
	return rn*m.cos(a*n), rn*m.sin(a*n)

def unit(k, n):
	k, n = k*1., n*1.
	return m.cos(2*k*m.pi/n), m.sin(2*k*m.pi/n)

def arange(start, stop, step=1):
	if start > stop:
		start, stop = stop, start
		step = abs(step)

	while start < stop:
		yield start
		start += step

def circle(n=10, r=3, c=(0,0)):
	ls = []

	for i in range(n):
		a = i*2*m.pi/n
		x,y = c[0] + r*m.cos(a), c[1] + r*m.sin(a)
		ls.append((x,y))

	return ls

def arc(n=10, r=3, c=(0,0), arg=m.pi):
	nls = []

	for i in range(n):
		a = i*arg/(n-1)
		x,y = c[0] + r*m.cos(a), c[1] + r*m.sin(a)
		nls.append((x,y))

	return nls

def square(n=5, inc=1, c=(0,0)):
	n = 5
	ls = []
	for i in arange(-n, n+1, inc):
		for j in arange(-n, n+1, inc):
			ls.append((c[0] + i, c[1] + j))

	return ls

def square2(p1, p2, p3, p4, n=5):
	ls = []

	ls += line(p1, p2, n)
	ls += line(p2, p3, n)
	ls += line(p3, p4, n)
	ls += line(p4, p1, n)

	return ls

def square3(p1, p2, n=5):
	ls = []
	x1,y1 = p1
	x2,y2 = p2
	dx, dy = x2-x1, y2-y1

	if abs(dx) > abs(dy):
		ny = n*float(dy)/dx
		nx = n
	else:
		ny = n
		nx = n*float(dx)/dy

	xr = float(dx)/nx
	yr = float(dy)/ny

	for i in arange(x1, x2, xr):
		for j in arange(y1, y2, yr):
			ls.append((i, j))

	return ls

def line(p1, p2, n):
	x1,y1 = p1
	x2,y2 = p2
	dx, dy = x2-x1, y2-y1
	m = dy/float(n)
	rdx = dx/float(n)

	ls = []
	for i in range(0, n):
		ls.append((x1+i*rdx, y1+i*m))

	return ls
		

def triangle(p1, p2, p3, n):
	ls = []

	ls += line(p1, p2, n)
	ls += line(p2, p3, n)
	ls += line(p3, p1, n)

	return ls

def triangle2(p1, p2, p3, n):
	ls = []

	ls += line(p1, p2, n)
	ls += line(p2, p3, n)
	ls += line(p3, p1, n)

	return ls

def polygon(k, n=10, r=3):
	ls = []

	for i in range(k):
		a = i*2*m.pi/k
		x,y = r*m.cos(a), r*m.sin(a)
		ls.append((x,y))

	nls = []
	for i in range(k):
		nls += line(ls[i-1], ls[i], n)

	return nls

def expand(ls, fact):
	for i in range(len(ls)):
		x,y = ls[i]
		ls[i] = (x*fact,y*fact)

	return ls

def exponential_analysis_arg(n):
	ls = []
	for k in range(n):
		r = 1
		arg = 2*m.pi*k/n
		ls.append((r * m.cos(arg), r * m.sin(arg)))

	return ls

def exponential_analysis_y(n, r):
	ls = []
	for k in range(n):
		ls.append((1, k*r/float(n)))

	return ls

if __name__ == '__main__':
	pl.init((320,320))
	c1 = colors.Colors((255,0,0), (0, 0, 255))
	c2 = colors.Colors((150,150,150), (200,200,200))
	sz = (6,6)
	p1 = pl.Plane(sz)
	p2 = pl.Plane(sz)
	ls = []

	#ls.append((int(round(x, 0)),int(round(y, 0))))

	#nls = line((-m.pi/2, 1.2), (m.pi/2, 1.2), 40)
	#nls = line((0.5, -m.pi/2), (0.5, m.pi/2), 40)
	#nls = square(5)
	#nls = arc(60, r=2.5, c=(0,0), arg=m.pi)
	#nls = triangle((-1.7, -1), (0,2), (1.7,-1), 30)
	#nls = triangle((-1,-1), (0,2), (1.0,-1.0), 15)
	#nls = square2((-2,-2), (-2,2), (2, 2), (2, -2), 5)
	#nls = circle(50, r=1, c=(1,1))
	nls = polygon(7, 15, r=1.5)
	#nls = square3((-2,-m.pi), (2,m.pi), 16)
	#nls = square3((2.1,-m.pi/2), (3.1,m.pi/2), 25)
	#nls = square3((-m.pi/4,-1.0), (m.pi/4,1.0), 17)
	#nls = square3((-5,-1), (5,-5), 15)
	#nls = square3((-.5,-m.pi), (.5, m.pi), 15)

	#nls = exponential_analysis_y(60, 200)

	#pprint.pprint(nls)

	z1 = 2 + 2j
	z2 = 1 + 1j

	for x,y in nls:
		z = x + y*1j
		#w = z / z2
		#w = z*z1 + z2
		#w = z**5
		#if z != 0: w = 1/z
		#else: w = z
		#w = cmath.sqrt(z)
		#r,t = cmath.polar(z)
		#t = (t + 2*1*m.pi)/2
		#w = m.sqrt(r) * (m.cos(t) + 1j*m.sin(t))
		#w = cmath.exp(z)
		#w = cmath.sin(z)
		w = cmath.cos(z)
		#w = cmath.log(z)
		x,y = w.real, w.imag

		ls.append((x,y))

	#pprint.pprint(nls)
	uc = circle(50, 1)
	ucls = circle(50, 1)

	exfac = 1.0
	expand(ucls, exfac)
	expand(ls, exfac)

	p1.plot((nls, c1))
	p1.plot((uc, c2))

	p2.plot((ls, c1))
	p2.plot((ucls, c2))

	pl.show()

	#pprint.pprint(nls)
